home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / compress / gnucpio.zip / COPYPASS.C < prev    next >
C/C++ Source or Header  |  1995-06-27  |  15KB  |  463 lines

  1. /* copypass.c - cpio copy pass sub-function.
  2.    Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <stdio.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include "filetypes.h"
  22. #include "system.h"
  23. #include "cpiohdr.h"
  24. #include "dstring.h"
  25. #include "extern.h"
  26.  
  27. #ifndef HAVE_LCHOWN
  28. #define lchown chown
  29. #endif
  30.  
  31. /* Copy files listed on the standard input into directory `directory_name'.
  32.    If `link_flag', link instead of copying.  */
  33.  
  34. void
  35. process_copy_pass ()
  36. {
  37.   dynamic_string input_name;    /* Name of file from stdin.  */
  38.   dynamic_string output_name;    /* Name of new file.  */
  39.   int dirname_len;        /* Length of `directory_name'.  */
  40.   int res;            /* Result of functions.  */
  41.   char *slash;            /* For moving past slashes in input name.  */
  42.   struct utimbuf times;        /* For resetting file times after copy.  */
  43.   struct stat in_file_stat;    /* Stat record for input file.  */
  44.   struct stat out_file_stat;    /* Stat record for output file.  */
  45.   int in_file_des;        /* Input file descriptor.  */
  46.   int out_file_des;        /* Output file descriptor.  */
  47.   int existing_dir;        /* True if file is a dir & already exists.  */
  48. #ifdef HPUX_CDF
  49.   int cdf_flag;
  50.   int cdf_char;
  51. #endif
  52.  
  53.   /* Initialize the copy pass.  */
  54.   dirname_len = strlen (directory_name);
  55.   ds_init (&input_name, 128);
  56.   ds_init (&output_name, dirname_len + 2);
  57.   strcpy (output_name.ds_string, directory_name);
  58.   output_name.ds_string[dirname_len] = '/';
  59.   output_is_seekable = TRUE;
  60.   /* Initialize this in case it has members we don't know to set.  */
  61.   bzero (×, sizeof (struct utimbuf));
  62.  
  63.   /* Copy files with names read from stdin.  */
  64.   while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
  65.     {
  66.       int link_res = -1;
  67.  
  68.       /* Check for blank line and ignore it if found.  */
  69.       if (input_name.ds_string[0] == '\0')
  70.     {
  71.       error (0, 0, "blank line ignored");
  72.       continue;
  73.     }
  74.  
  75.       /* Check for current directory and ignore it if found.  */
  76.       if (input_name.ds_string[0] == '.'
  77.       && (input_name.ds_string[1] == '\0'
  78.           || (input_name.ds_string[1] == '/'
  79.           && input_name.ds_string[2] == '\0')))
  80.     continue;
  81.  
  82.       if ((*xstat) (input_name.ds_string, &in_file_stat) < 0)
  83.     {
  84.       error (0, errno, "%s", input_name.ds_string);
  85.       continue;
  86.     }
  87.  
  88.       /* Make the name of the new file.  */
  89.       for (slash = input_name.ds_string; *slash == '/'; ++slash)
  90.     ;
  91. #ifdef HPUX_CDF
  92.       /* For CDF's we add a 2nd `/' after all "hidden" directories.
  93.      This kind of a kludge, but it's what we do when creating
  94.      archives, and it's easier to do this than to separately
  95.      keep track of which directories in a path are "hidden".  */
  96.       slash = add_cdf_double_slashes (slash);
  97. #endif
  98.       ds_resize (&output_name, dirname_len + strlen (slash) + 2);
  99.       strcpy (output_name.ds_string + dirname_len + 1, slash);
  100.  
  101.       existing_dir = FALSE;
  102.       if (lstat (output_name.ds_string, &out_file_stat) == 0)
  103.     {
  104.       if (S_ISDIR (out_file_stat.st_mode)
  105.           && S_ISDIR (in_file_stat.st_mode))
  106.         {
  107.           /* If there is already a directory there that
  108.          we are trying to create, don't complain about it.  */
  109.           existing_dir = TRUE;
  110.         }
  111.       else if (!unconditional_flag
  112.            && in_file_stat.st_mtime <= out_file_stat.st_mtime)
  113.         {
  114.           error (0, 0, "%s not created: newer or same age version exists",
  115.              output_name.ds_string);
  116.           continue;        /* Go to the next file.  */
  117.         }
  118.       else if (S_ISDIR (out_file_stat.st_mode)
  119.             ? rmdir (output_name.ds_string)
  120.             : unlink (output_name.ds_string))
  121.         {
  122.           error (0, errno, "cannot remove current %s",
  123.              output_name.ds_string);
  124.           continue;        /* Go to the next file.  */
  125.         }
  126.     }
  127.  
  128.       /* Do the real copy or link.  */
  129.       if (S_ISREG (in_file_stat.st_mode))
  130.     {
  131. #ifndef __MSDOS__
  132.       /* Can the current file be linked to a another file?
  133.          Set link_name to the original file name.  */
  134.       if (link_flag)
  135.         /* User said to link it if possible.  Try and link to
  136.            the original copy.  If that fails we'll still try
  137.            and link to a copy we've already made.  */
  138.         link_res = link_to_name (output_name.ds_string, 
  139.                      input_name.ds_string);
  140.       if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
  141.         link_res = link_to_maj_min_ino (output_name.ds_string, 
  142.                 major (in_file_stat.st_dev), 
  143.                 minor (in_file_stat.st_dev), 
  144.                 in_file_stat.st_ino);
  145. #endif
  146.  
  147.       /* If the file was not linked, copy contents of file.  */
  148.       if (link_res < 0)
  149.         {
  150.           in_file_des = open (input_name.ds_string,
  151.                   O_RDONLY | O_BINARY, 0);
  152.           if (in_file_des < 0)
  153.         {
  154.           error (0, errno, "%s", input_name.ds_string);
  155.           continue;
  156.         }
  157.           out_file_des = open (output_name.ds_string,
  158.                    O_CREAT | O_WRONLY | O_BINARY, 0600);
  159.           if (out_file_des < 0 && create_dir_flag)
  160.         {
  161.           create_all_directories (output_name.ds_string);
  162.           out_file_des = open (output_name.ds_string,
  163.                        O_CREAT | O_WRONLY | O_BINARY, 0600);
  164.         }
  165.           if (out_file_des < 0)
  166.         {
  167.           error (0, errno, "%s", output_name.ds_string);
  168.           close (in_file_des);
  169.           continue;
  170.         }
  171.  
  172.           copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string);
  173.           disk_empty_output_buffer (out_file_des);
  174.           if (close (in_file_des) < 0)
  175.         error (0, errno, "%s", input_name.ds_string);
  176.           if (close (out_file_des) < 0)
  177.         error (0, errno, "%s", output_name.ds_string);
  178.  
  179.           /* Set the attributes of the new file.  */
  180.           if (!no_chown_flag)
  181.         if ((chown (output_name.ds_string,
  182.                 set_owner_flag ? set_owner : in_file_stat.st_uid,
  183.               set_group_flag ? set_group : in_file_stat.st_gid) < 0)
  184.             && errno != EPERM)
  185.           error (0, errno, "%s", output_name.ds_string);
  186.           /* chown may have turned off some permissions we wanted. */
  187.           if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
  188.         error (0, errno, "%s", output_name.ds_string);
  189.           if (reset_time_flag)
  190.         {
  191.           times.actime = in_file_stat.st_atime;
  192.           times.modtime = in_file_stat.st_mtime;
  193.           if (utime (input_name.ds_string, ×) < 0)
  194.             error (0, errno, "%s", input_name.ds_string);
  195.           if (utime (output_name.ds_string, ×) < 0)
  196.             error (0, errno, "%s", output_name.ds_string);
  197.         }
  198.           if (retain_time_flag)
  199.         {
  200.           times.actime = times.modtime = in_file_stat.st_mtime;
  201.           if (utime (output_name.ds_string, ×) < 0)
  202.             error (0, errno, "%s", output_name.ds_string);
  203.         }
  204.         }
  205.     }
  206.       else if (S_ISDIR (in_file_stat.st_mode))
  207.     {
  208. #ifdef HPUX_CDF
  209.       cdf_flag = 0;
  210. #endif
  211.       if (!existing_dir)
  212.         {
  213. #ifdef HPUX_CDF
  214.           /* If the directory name ends in a + and is SUID,
  215.          then it is a CDF.  Strip the trailing + from the name
  216.          before creating it.  */
  217.           cdf_char = strlen (output_name.ds_string) - 1;
  218.           if ( (cdf_char > 0) &&
  219.            (in_file_stat.st_mode & 04000) &&
  220.            (output_name.ds_string [cdf_char] == '+') )
  221.         {
  222.           output_name.ds_string [cdf_char] = '\0';
  223.           cdf_flag = 1;
  224.         }
  225. #endif
  226.           res = mkdir (output_name.ds_string, in_file_stat.st_mode);
  227.  
  228.         }
  229.       else
  230.         res = 0;
  231.       if (res < 0 && create_dir_flag)
  232.         {
  233.           create_all_directories (output_name.ds_string);
  234.           res = mkdir (output_name.ds_string, in_file_stat.st_mode);
  235.         }
  236.       if (res < 0)
  237.         {
  238.           /* In some odd cases where the output_name includes `.',
  239.              the directory may have actually been created by
  240.              create_all_directories(), so the mkdir will fail
  241.              because the directory exists.  If that's the case,
  242.              don't complain about it.  */
  243.           if ( (errno != EEXIST) ||
  244.                  (lstat (output_name.ds_string, &out_file_stat) != 0) ||
  245.                !(S_ISDIR (out_file_stat.st_mode) ) )
  246.         {
  247.           error (0, errno, "%s", output_name.ds_string);
  248.           continue;
  249.         }
  250.         }
  251.       if (!no_chown_flag)
  252.         if ((chown (output_name.ds_string,
  253.             set_owner_flag ? set_owner : in_file_stat.st_uid,
  254.               set_group_flag ? set_group : in_file_stat.st_gid) < 0)
  255.         && errno != EPERM)
  256.           error (0, errno, "%s", output_name.ds_string);
  257.       /* chown may have turned off some permissions we wanted. */
  258.       if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
  259.         error (0, errno, "%s", output_name.ds_string);
  260. #ifdef HPUX_CDF
  261.       if (cdf_flag)
  262.         /* Once we "hide" the directory with the chmod(),
  263.            we have to refer to it using name+ isntead of name.  */
  264.         output_name.ds_string [cdf_char] = '+';
  265. #endif
  266.       if (retain_time_flag)
  267.         {
  268.           times.actime = times.modtime = in_file_stat.st_mtime;
  269.           if (utime (output_name.ds_string, ×) < 0)
  270.         error (0, errno, "%s", output_name.ds_string);
  271.         }
  272.     }
  273. #ifndef __MSDOS__
  274.       else if (S_ISCHR (in_file_stat.st_mode) ||
  275.            S_ISBLK (in_file_stat.st_mode) ||
  276. #ifdef S_ISFIFO
  277.            S_ISFIFO (in_file_stat.st_mode) ||
  278. #endif
  279. #ifdef S_ISSOCK
  280.            S_ISSOCK (in_file_stat.st_mode) ||
  281. #endif
  282.            0)
  283.     {
  284.       /* Can the current file be linked to a another file?
  285.          Set link_name to the original file name.  */
  286.       if (link_flag)
  287.         /* User said to link it if possible.  */
  288.         link_res = link_to_name (output_name.ds_string, 
  289.                      input_name.ds_string);
  290.       if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
  291.         link_res = link_to_maj_min_ino (output_name.ds_string, 
  292.             major (in_file_stat.st_dev),
  293.             minor (in_file_stat.st_dev),
  294.             in_file_stat.st_ino);
  295.  
  296.       if (link_res < 0)
  297.         {
  298.           res = mknod (output_name.ds_string, in_file_stat.st_mode,
  299.                in_file_stat.st_rdev);
  300.           if (res < 0 && create_dir_flag)
  301.         {
  302.           create_all_directories (output_name.ds_string);
  303.           res = mknod (output_name.ds_string, in_file_stat.st_mode,
  304.                    in_file_stat.st_rdev);
  305.         }
  306.           if (res < 0)
  307.         {
  308.           error (0, errno, "%s", output_name.ds_string);
  309.           continue;
  310.         }
  311.           if (!no_chown_flag)
  312.         if ((chown (output_name.ds_string,
  313.                 set_owner_flag ? set_owner : in_file_stat.st_uid,
  314.               set_group_flag ? set_group : in_file_stat.st_gid) < 0)
  315.             && errno != EPERM)
  316.           error (0, errno, "%s", output_name.ds_string);
  317.           /* chown may have turned off some permissions we wanted. */
  318.           if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
  319.         error (0, errno, "%s", output_name.ds_string);
  320.           if (retain_time_flag)
  321.         {
  322.           times.actime = times.modtime = in_file_stat.st_mtime;
  323.           if (utime (output_name.ds_string, ×) < 0)
  324.             error (0, errno, "%s", output_name.ds_string);
  325.         }
  326.         }
  327.     }
  328. #endif
  329.  
  330. #ifdef S_ISLNK
  331.       else if (S_ISLNK (in_file_stat.st_mode))
  332.     {
  333.       char *link_name;
  334.       link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);
  335.  
  336.       if (readlink (input_name.ds_string, link_name,
  337.             in_file_stat.st_size) < 0)
  338.         {
  339.           error (0, errno, "%s", input_name.ds_string);
  340.           free (link_name);
  341.           continue;
  342.         }
  343.       link_name[in_file_stat.st_size] = '\0';
  344.  
  345.       res = UMASKED_SYMLINK (link_name, output_name.ds_string,
  346.                  in_file_stat.st_mode);
  347.       if (res < 0 && create_dir_flag)
  348.         {
  349.           create_all_directories (output_name.ds_string);
  350.           res = UMASKED_SYMLINK (link_name, output_name.ds_string,
  351.                      in_file_stat.st_mode);
  352.         }
  353.       if (res < 0)
  354.         {
  355.           error (0, errno, "%s", output_name.ds_string);
  356.           free (link_name);
  357.           continue;
  358.         }
  359.  
  360.       /* Set the attributes of the new link.  */
  361.       if (!no_chown_flag)
  362.         if ((lchown (output_name.ds_string,
  363.              set_owner_flag ? set_owner : in_file_stat.st_uid,
  364.               set_group_flag ? set_group : in_file_stat.st_gid) < 0)
  365.         && errno != EPERM)
  366.           error (0, errno, "%s", output_name.ds_string);
  367.       free (link_name);
  368.     }
  369. #endif
  370.       else
  371.     {
  372.       error (0, 0, "%s: unknown file type", input_name.ds_string);
  373.     }
  374.  
  375.       if (verbose_flag)
  376.     fprintf (stderr, "%s\n", output_name.ds_string);
  377.       if (dot_flag)
  378.     fputc ('.', stderr);
  379.     }
  380.  
  381.   if (dot_flag)
  382.     fputc ('\n', stderr);
  383.   if (!quiet_flag)
  384.     {
  385.       res = (output_bytes + io_block_size - 1) / io_block_size;
  386.       if (res == 1)
  387.     fprintf (stderr, "1 block\n");
  388.       else
  389.     fprintf (stderr, "%d blocks\n", res);
  390.     }
  391. }
  392.  
  393. /* Try and create a hard link from FILE_NAME to another file 
  394.    with the given major/minor device number and inode.  If no other
  395.    file with the same major/minor/inode numbers is known, add this file
  396.    to the list of known files and associated major/minor/inode numbers
  397.    and return -1.  If another file with the same major/minor/inode
  398.    numbers is found, try and create another link to it using
  399.    link_to_name, and return 0 for success and -1 for failure.  */
  400.  
  401. int
  402. link_to_maj_min_ino (file_name, st_dev_maj, st_dev_min, st_ino)
  403.   char *file_name;
  404.   int st_dev_maj;
  405.   int st_dev_min;
  406.   int st_ino;
  407. {
  408.   int    link_res;
  409.   char *link_name;
  410.   link_res = -1;
  411. #ifndef __MSDOS__
  412.   /* Is the file a link to a previously copied file?  */
  413.   link_name = find_inode_file (st_ino,
  414.                    st_dev_maj,
  415.                    st_dev_min);
  416.   if (link_name == NULL)
  417.     add_inode (st_ino, file_name,
  418.            st_dev_maj,
  419.            st_dev_min);
  420.   else
  421.     link_res = link_to_name (file_name, link_name);
  422. #endif
  423.   return link_res;
  424. }
  425.  
  426. /* Try and create a hard link from LINK_NAME to LINK_TARGET.  If
  427.    `create_dir_flag' is set, any non-existent (parent) directories 
  428.    needed by LINK_NAME will be created.  If the link is successfully
  429.    created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n".
  430.    If the link can not be created and `link_flag' is set, print
  431.    "cannot link LINK_TARGET to LINK_NAME\n".  Return 0 if the link
  432.    is created, -1 otherwise.  */
  433.  
  434. int
  435. link_to_name (link_name, link_target)
  436.   char *link_name;
  437.   char *link_target;
  438. {
  439.   int res;
  440. #ifdef __MSDOS__
  441.   res = -1;
  442. #else /* not __MSDOS__ */
  443.   res = link (link_target, link_name);
  444.   if (res < 0 && create_dir_flag)
  445.     {
  446.       create_all_directories (link_name);
  447.       res = link (link_target, link_name);
  448.     }
  449.   if (res == 0)
  450.     {
  451.       if (verbose_flag)
  452.     error (0, 0, "%s linked to %s",
  453.            link_target, link_name);
  454.     }
  455.   else if (link_flag)
  456.     {
  457.       error (0, errno, "cannot link %s to %s",
  458.          link_target, link_name);
  459.     }
  460. #endif /* not __MSDOS__ */
  461.   return res;
  462. }
  463.